﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PACKETPARSERMAX20.CORE
{
    public class WoWCore
    {
        //private int mClientBuild = 0;
        //private string mAccountName = "";
        //private ulong PlayerGUID = 0;
        //private uint mMapID = 0;
        //private string mWorldServerMsg = "";
        //private string mGuildEventMsg = "";
        //private uint mZoneID = 0;
        //private int mAreaTriggerID = 0;
        //private SortedList<UInt64, WoWObjectBase> mObjList = null;
        //private SortedList<UInt64, UInt64> mAltObjList = null;

        //public uint CurrentBattleGroundTypeId = 0;
        //public FactionHandler factionHandler = null;

        public SortedList<uint, string> PetNameByNumberList = new SortedList<uint, string>();
        public SortedList<ulong, CharEnumInfo> CharEnumInfoList = new SortedList<ulong, CharEnumInfo>();

        public DateTime updateTimer = DateTime.Now;

        public class NameQueryResponseInfo
        {
            public string Name;
            public string BgRealm;
            public UInt32 Race;
            public UInt32 Gender;
            public UInt32 Class;
        }

        public System.Collections.Generic.SortedList<ulong, NameQueryResponseInfo> NameQueryResponseInfoList { get; set; }
        public System.Collections.Specialized.StringCollection ChatList { get; set; }

        public PACKETPARSERMAX20.EventManager EventManager = null;
        public int ClientBuild { get; private set; }
        public string AccountName { get; private set; }
        public UInt64 PlayerGUID { get; private set; }
        public uint MapID { get; private set; }
        public uint ZoneID { get; private set; }
        public int AreaTriggerID { get; set; }
        public SortedList<UInt64, WoWObjectBase> ObjList { get; private set; }
        public SortedList<UInt64, UInt64> AltObjList { get; private set; }
        public FactionHandler FactionHandler { get; private set; }

        public WoWCore(PACKETPARSERMAX20.EventManager pEventManager)
        {
            EventManager = pEventManager;
            NameQueryResponseInfoList = new SortedList<ulong, NameQueryResponseInfo>();
            ChatList = new System.Collections.Specialized.StringCollection();
            ObjList = new SortedList<UInt64, WoWObjectBase>();
            AltObjList = new SortedList<ulong, ulong>();
        }

        public WoWObjectPlayer Player
        {
            get
            {
                return (WoWObjectPlayer)CreateOrGetObject(PlayerGUID, TypeID.TYPEID_PLAYER);
            }
        }


        public void Load_CMSG_AUTH_SESSION(int clientbuild, string accountname)
        {
            ClientBuild = clientbuild;
            AccountName = accountname;
            //if (!StaticObjects.DataCaptureList.ContainsKey(clientbuild))
            //{
            //    StaticObjects.DataCaptureList.Add(clientbuild, new DataCapture(clientbuild));
            //}
            //Capture = StaticObjects.DataCaptureList[clientbuild];
            FactionHandler = new FactionHandler(ClientBuild);
        }

        public void Load_SMSG_LOGIN_VERIFY_WORLD(uint mapid, float x, float y, float z, float o)
        {
            MapID = mapid;

            if (CharEnumInfoList.Count > 0)
            {
                ZoneID = CharEnumInfoList[PlayerGUID].ZoneId;

                Player.UpdateObjectPosition(x, y, z, o, 0);

                Load_CMSG_ZONEUPDATE(ZoneID);
            };
        }

        public void Load_CMSG_ZONEUPDATE(uint zoneid)
        {
            ZoneID = zoneid;

            System.Data.DataRow tRow = PACKETPARSERMAX20.Support.areaTable.Rows.Find(ZoneID.ToString());

            if (tRow != null)
            {
               MapID = uint.Parse(tRow["mapid"].ToString());

                Update();
            }
        }

        public void Load_CMSG_PLAYER_LOGIN(ulong guid)
        {
            PlayerGUID = guid;
        }
 
        public void Load_SMSG_NAME_QUERY_RESPONSE(UInt64 guid, string pName, string pbgrealm, UInt32 pRace, UInt32 pGender, UInt32 pClass)
        {

            WoWObjectBase obj = GetObject(guid);
            if (obj != null)
            {
                if (obj is WoWObjectUnit)
                {
                    ((WoWObjectUnit)obj).Name = pName;
                    ((WoWObjectUnit)obj).BgRealm = pbgrealm;
                    ((WoWObjectUnit)obj).Race = pRace;
                    ((WoWObjectUnit)obj).Gender = pGender;
                    ((WoWObjectUnit)obj).Class = pClass;
                }
                else if (obj is WoWObjectPlayer)
                {
                    ((WoWObjectPlayer)obj).Name = pName;
                    ((WoWObjectPlayer)obj).BgRealm = pbgrealm;
                    ((WoWObjectPlayer)obj).Race = pRace;
                    ((WoWObjectPlayer)obj).Gender = pGender;
                    ((WoWObjectPlayer)obj).Class = pClass;
                }
            }
            if (NameQueryResponseInfoList.ContainsKey(guid)) { NameQueryResponseInfoList.Remove(guid); }
            NameQueryResponseInfoList.Add(guid, new NameQueryResponseInfo() { Name = pName, BgRealm = pbgrealm, Class = pClass, Gender = pGender, Race = pRace });

        }

        public WoWObjectBase GetObject(UInt64 guid)
        {
            if (ObjList.ContainsKey(guid))
            {
                return ObjList[guid];
            }
            else if (AltObjList.ContainsKey(guid))
            {
                return ObjList[AltObjList[guid]];
            }
            return null;
        }

        public WoWObjectBase CreateOrGetObject(UInt64 guid, TypeID typeid)
        {
            var createdObject = GetObject(guid);

            if (createdObject == null)
            {
                switch (typeid)
                {
                    case TypeID.TYPEID_ITEM:
                        createdObject = new WoWObjectItem(this, guid, typeid);
                        break;
                    case TypeID.TYPEID_CONTAINER:
                        createdObject = new WoWObjectContainer(this, guid, typeid);
                        break;
                    case TypeID.TYPEID_UNIT:
                        createdObject = new WoWObjectUnit(this, guid, typeid);
                        break;
                    case TypeID.TYPEID_PLAYER:
                        createdObject = new WoWObjectPlayer(this, guid, typeid);
                        break;
                    case TypeID.TYPEID_GAMEOBJECT:
                        createdObject = new WoWObjectGameObject(this, guid, typeid);
                        break;
                    case TypeID.TYPEID_CORPSE:
                        createdObject = new WoWObjectCorpse(this, guid, typeid);
                        break;
                    case TypeID.TYPEID_DYNAMICOBJECT:
                        createdObject = new WoWObjectDynamicObject(this, guid, typeid);
                        break;
                    default:
                        throw new Exception(string.Format("CreateOrGetObject Unknown TypeID {0}.", typeid));
                }

                ObjList.Add(guid, createdObject);

            }
            return createdObject;
        }

        public void RemoveObject(UInt64 guid)
        {
            if (ObjList.ContainsKey(guid))
            {
                if (AltObjList.ContainsKey(ObjList[guid].OBJECT_FIELD_GUID))
                    AltObjList.Remove(ObjList[guid].OBJECT_FIELD_GUID);
                ObjList.Remove(guid);

            }
            else
            {
                WoWObjectBase tobj = GetObject(guid);
                if (tobj != null)
                {
                    if (AltObjList.ContainsKey(tobj.OBJECT_FIELD_GUID))
                        AltObjList.Remove(tobj.OBJECT_FIELD_GUID);
                    ObjList.Remove(tobj.Guid);
                }
                else
                {
                    //System.Diagnostics.Debug.WriteLine("REMOVING ALREADY REMOVED OBJECT!! ARE YOU DEBUGGING?");
                }
            }
        }

        public void Update()
        {
            //if ((DateTime.Now - updateTimer).Milliseconds > 1)
            //{
            EventManager.Object_Updated(this);
            //    updateTimer = DateTime.Now;
            //}
        }


        //#region Creature
        //public void SetCreatureName(uint pEntry, string pName)
        //{
        //    CreatureNameByEntryList[pEntry] = pName;
        //}
        //#endregion

        //#region "GameObject"

        //public void SetGameObjectName(uint pEntry, string pName)
        //{
        //    GameObjectNameByEntryList[pEntry] = pName;
        //}

        //#endregion

        //#region "Item"

        //public void SetItemName(uint pEntry, string pName)
        //{
        //    ItemNameByEntryList[pEntry] = pName;
        //}

        //#endregion

        #region "Object"

        public void UpdateObjectPosition(ulong guid, MovementInfo movementinfo, string source)
        {
            UpdateObjectPosition(guid, movementinfo.positionInfo.X, movementinfo.positionInfo.Y, movementinfo.positionInfo.Z, movementinfo.timeStamp, source);
        }

        public void UpdateObjectPosition(ulong guid, float x, float y, float z, uint time, string pSource)
        {
            var obj = GetObject(guid);
            if (obj != null && (x != 0f || y != 0f || z != 0f))
            {
                obj.UpdateObjectPosition(x, y, z, GetAngle(x, y, obj.X, obj.Y), time);
                Update();
            }
        }

        public void UpdateObjectPosition(ulong guid, float x, float y, float z, float o, uint time, string source)
        {
            WoWObjectBase tObj = GetObject(guid);

            if (tObj != null && (x != 0f || y != 0f || z != 0f || o != 0f))
            {
                tObj.UpdateObjectPosition(x, y, z, o, time);
                Update();
            }
        }

        //private float GetAngle(double x, double y, double oldx, double oldy)
        //{
        //    double dx = x - oldx;
        //    double dy = y - oldy;

        //    double ang = Math.Atan2(dy, dx);
        //    ang = (ang >= 0) ? ang : 2 * Math.PI + ang;
        //    return (float)ang;
        //}

        internal float GetAngle(float x, float y, float oldx, float oldy)
        {
            //float dx =  x - oldx;
            //float dy = y - oldy;

            float dx = (oldy - y);
            float dy = (x - oldx);

            float newRad = 0;
            if (dx > 0.0 && dy >= 0.0) newRad = (float)Math.Atan(dy / dx);
            if (dx < 0.0 && dy >= 0.0) newRad = (float)Math.Atan(dy / dx) + (float)Math.PI;
            if (dx < 0.0 && dy < 0.0) newRad = (float)Math.Atan(dy / dx) + (float)Math.PI;
            if (dx > 0.0 && dy < 0.0) newRad = (float)Math.Atan(dy / dx) + (float)(2 * Math.PI);

            newRad -= (float)1.57079633;  //silly game making zero degrees due East

            return newRad;
        }
        #endregion

        #region Pet

        public void SetPetName(uint pPetnumber, string pName)
        {
            if (!PetNameByNumberList.ContainsKey(pPetnumber))
                PetNameByNumberList.Add(pPetnumber, pName);
            else
                PetNameByNumberList[pPetnumber] = pName;
        }
        #endregion

        #region Player

        public void SetCharEnumInfo(CharEnumInfo pCharEnumInfo)
        {
            CharEnumInfoList[pCharEnumInfo.Guid] = pCharEnumInfo;
        }
        #endregion


        public float CalculateAngle(float x1, float y1, float x2, float y2)
        {
            float dx = x2 - x1;
            float dy = y2 - y1;
            double angle = 0.0f;

            // Calculate angle
            if (dx == 0.0)
            {
                if (dy == 0.0)
                    angle = 0.0;
                else if (dy > 0.0)
                    angle = Math.PI * 0.5;
                else
                    angle = Math.PI * 3.0 * 0.5;
            }
            else if (dy == 0.0)
            {
                if (dx > 0.0)
                    angle = 0.0;
                else
                    angle = Math.PI;
            }
            else
            {
                if (dx < 0.0)
                    angle = Math.Atan(dy / dx) + Math.PI;
                else if (dy < 0.0)
                    angle = Math.Atan(dy / dx) + (2 * Math.PI);
                else
                    angle = Math.Atan(dy / dx);
            }

            return (float)angle;
        }


        public bool IsGuidPlayer(ulong? guid)
        {
            if (guid == null) return false;
            return guid.Value.ToString().StartsWith("4") ? true : false;
            //var obj = GetObject(guid.Value);
            //if (obj == null)
            //{
            //    return false;
            //}
            //return obj.typeid == TypeID.TYPEID_PLAYER;
        }

    }
}

